﻿
Imports System.Threading
Imports std

Public Class tcpTalk4
    Inherits tcpTalk3
    Private Shared ReadOnly TCPTALK4_REQUEST_QPS As Int64
    Private Shared ReadOnly TCPTALK4_TALK_TIMEMS As Int64
    Private Shared ReadOnly TCPTALK4_CONNECT_TIMEMS As Int64
    Private se As singleentry = Nothing

    Shared Sub New()
        TCPTALK4_REQUEST_QPS = counter.registerRateAndLastRate("TCPTALK4_REQUEST_QPS")
        TCPTALK4_TALK_TIMEMS = counter.registerAverageAndLastAverage("TCPTALK4_TALK_TIMEMS")
        TCPTALK4_CONNECT_TIMEMS = counter.registerAverageAndLastAverage("TCPTALK4_CONNECT_TIMEMS")
    End Sub

    Public Sub New()
        MyBase.New()
        se = New singleentry()
    End Sub

    Private Function connect_ec(ByVal addresses As vector(Of IPAddress2),
                                ByVal result As pointer(Of ternary)) As eventComb
        assert(Not addresses Is Nothing AndAlso addresses.size() > 0)
        assert(Not connected())
        Dim startMs As Int64 = 0
        Return eventCombAsyncOperation.ctor(Function(ByRef a As AsyncCallback, ByRef obj As Object) As IAsyncResult
                                                startMs = Now.milliseconds()
                                                Return connect_begin(a, obj, addresses)
                                            End Function,
                                            Function(ByRef a As IAsyncResult) As ternary
                                                counter.recordTimeMs(TCPTALK4_CONNECT_TIMEMS, startMs)
                                                Return connect_end(a)
                                            End Function,
                                            result)
    End Function

    Private Overloads Function connect(ByRef addresses As vector(Of IPAddress2),
                                       ByRef result As pointer(Of ternary),
                                       ByRef ec As eventComb) As Boolean
        ec = connect_ec(addresses, result)
        Return True
    End Function

    Private Overloads Function connect(ByRef ec As eventComb, ByVal result As pointer(Of ternary)) As Boolean
        Return connect(AddressOf connect, result, ec)
    End Function

    Private Function remainingMs(ByVal startticks As Int64) As Int64
        Return holdTimeMs - ticksToMilliseconds(Now.Ticks() - startticks)
    End Function

    Private Function send(ByRef ec As eventComb, ByVal startticks As Int64) As Boolean
        Dim conec As eventComb = Nothing
        Dim sendec As eventComb = Nothing
        Dim result As pointer(Of ternary) = Nothing
        ec = New eventComb(Function() As Boolean
                               If connected() Then
                                   Return goto_next() AndAlso goto_next()
                               Else
                                   result = New pointer(Of ternary)()
                                   Return connect(conec, result) AndAlso
                                          waitfor(conec, remainingMs(startticks)) AndAlso
                                          goto_next()
                               End If
                           End Function,
                           Function() As Boolean
                               If conec.end_result() Then
                                   _connected = result.get()
                                   Return goto_prev()
                               Else
                                   Return False
                               End If
                           End Function,
                           Function() As Boolean
                               Return tcpTrans4.send(client(), senddata(), remainingMs(startticks), sendec) AndAlso
                                      waitfor(sendec) AndAlso
                                      goto_next()
                           End Function,
                           Function() As Boolean
                               Return eventComb.success_behavior(sendec,
                                                                 Sub()
                                                                     goto_end()
                                                                 End Sub,
                                                                 Sub()
                                                                     _connected = ternary.false
                                                                 End Sub)
                           End Function)
        Return True
    End Function

    Private Function receive(ByRef ec As eventComb, ByVal startticks As Int64) As Boolean
        Dim recec As eventComb = Nothing
        ec = New eventComb(Function() As Boolean
                               Return connected() AndAlso
                                      tcpTrans4.receive(client(),
                                                        receivedata(),
                                                        remainingMs(startticks),
                                                        ec:=recec) AndAlso
                                      waitfor(recec) AndAlso
                                      [goto](1)
                           End Function,
                           Function() As Boolean
                               counter.recordTimeMs(TCPTALK4_TALK_TIMEMS, ticksToMilliseconds(startticks))
                               updateLastFinishTicks()
                               Return goto_end() AndAlso recec.end_result()
                           End Function)
        Return True
    End Function

    Public Shadows Function talk(Optional ByRef ec As eventComb = Nothing) As Boolean
        Dim sendec As eventComb = Nothing
        Dim recec As eventComb = Nothing
        Dim startticks As Int64 = 0
        startticks = Now.Ticks()
        ec = New eventComb(Function() As Boolean
                               Return se.mark_in_use() AndAlso
                                      send(sendec, startticks) AndAlso
                                      waitfor(sendec) AndAlso
                                      [goto](1)
                           End Function,
                           Function() As Boolean
                               Return receive(recec, startticks) AndAlso
                                      waitfor(recec) AndAlso
                                      [goto](2)
                           End Function,
                           Function() As Boolean
                               se.release()
                               Return goto_end() AndAlso recec.end_result()
                           End Function)
        Return True
    End Function

    Public Overloads Sub connect(ByVal host As String, ByVal port As Int32, ByRef ec As eventComb)
        Dim conec As eventComb = Nothing
        connect(host, port, conec, AddressOf connect)
        If conec Is Nothing Then
            ec = Nothing
        Else
            ec = New eventComb(Function() As Boolean
                                   Return se.mark_in_use() AndAlso waitfor(conec) AndAlso [goto](1)
                               End Function,
                               Function() As Boolean
                                   se.release()
                                   Return goto_end() AndAlso conec.end_result()
                               End Function)
        End If
    End Sub

    Public Overrides Sub connect(ByVal host As String, ByVal port As Int32)
        Dim ec As eventComb = Nothing
        connect(host, port, ec)
        If Not ec Is Nothing Then
            assert_begin(ec)
        End If
    End Sub
End Class

Public Class talk4pool_t
    Inherits talkXpool_t(Of tcpTalk4)
End Class

Public Class fixpoint_talk4pool_t
    Inherits fixpoint_talkXpool_t(Of tcpTalk4)

    Public Sub New(ByVal host As String, ByVal port As Int32,
                   Optional ByVal holdtimeMs As Int64 = tcpTalk3.defaultHoldTimeMs,
                   Optional ByVal livetimeMs As Int64 = tcpTalk3.defaultLiveTimeMs)
        MyBase.new(host, port, holdtimeMs, livetimeMs)
    End Sub
End Class
